using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;


namespace WindowsApplicationLZ77
{
    public partial class FormLZ77 : Form
    {
        private OpenFileDialog openFileDialog = null;
        private StreamReader streamReader = null;
        private string ruta = "";
        private int cantidadBytes;
        private Hashtable hashTableFrecuencias = null;

        private Dato[] listaFrecuencias = null;
        private int    _actualLF = 0;

        public FormLZ77()
        {
            InitializeComponent();
            hashTableFrecuencias = new Hashtable();
        }

        #region EVENTOS
        private void buttonBuscar_Click(object sender, EventArgs e)
        {
            openFileDialog = new OpenFileDialog();
            openFileDialog.FileName = "LZ.txt";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                ruta = openFileDialog.FileName;
                if (ruta == null || ruta == "")
                    return;

                textBoxRutaArchivo.Text = ruta;
                buttonComprimir.Enabled = true;
            }

        }


        ArbolHuffman _arbolHuffman = null;
        private void buttonComprimir_Click(object sender, EventArgs e)
        {
            this.buttonComprimir.Enabled = false;
            CargarHasTable(ruta);
            CargarListaConFrecuencias(ruta);
            _arbolHuffman = new ArbolHuffman(listaFrecuencias, _actualLF);

            panel1.Invalidate();
            //
            Comprimir();

           // System.Console.WriteLine("GetCodigo( 'A' ): " + arbolHuffman.GetCodigo(arbolHuffman.Raiz,'A') );
           // System.Console.WriteLine("GetCodigo( 'B' ): " + arbolHuffman.GetCodigo(arbolHuffman.Raiz, 'B'));
        }


        private Pen lapiz = new Pen(Color.Red);
        
        //private int _yIni = 0;
        private int _DELTA_Y = 30;
        private int _DELTA_X;
        private int _CONST = 400;
        int _xIni;
        int _yIni;
        private void MostrarArbol(Nodo raiz, int xAnt, int yAnt, bool esNodoDerecho,int altura, Graphics g)
        {
                double cantidadNodosAncho = Math.Pow(2, altura);
                //_DELTA_X = Ancho del panel donde se dibuja
                double _DELTA_X = _CONST / cantidadNodosAncho;

                //Dibujo a izquierda o derecha
                int nuevoX = -1;
                int nuevoY = yAnt + _DELTA_Y;

                if (esNodoDerecho)
                {
                    nuevoX = xAnt + (int)(_DELTA_X / 2);
                    g.DrawLine(lapiz, new Point(xAnt, yAnt), new Point(nuevoX, nuevoY));
                    string s = "(" + raiz.Dato.Caracter.ToString() + "," + raiz.Peso + ")";
                    g.DrawString(s, new Font("Verdana", 8), new SolidBrush(Color.Black), nuevoX - 20, nuevoY);
                }
                else
                {
                    nuevoX = xAnt - (int)_DELTA_X;
                    g.DrawLine(lapiz, new Point(xAnt, yAnt), new Point(nuevoX, nuevoY));
                    string s = "(" + raiz.Dato.Caracter.ToString() + "," + raiz.Peso + ")";
                    g.DrawString(s, new Font("Verdana", 8), new SolidBrush(Color.Black), nuevoX - 20, nuevoY);
                }

                int i = altura + 1;
                if (raiz.NodoDer != null)
                    MostrarArbol(raiz.NodoDer, nuevoX, nuevoY, true, i, g);

                if (raiz.NodoIzq != null)
                    MostrarArbol(raiz.NodoIzq, nuevoX, nuevoY, false, i, g);
        }

        #endregion

        #region LISTA-ARRAY

        public void CargarListaConFrecuencias(string ruta)
        {
            listaFrecuencias = new Dato[cantidadBytes];
            streamReader = new StreamReader(ruta);
            if (streamReader == null)
                return;

            int i;
            cantidadBytes = 0;
            Dato dato = null;
            System.Console.WriteLine("StreamReader.Lenght = " + streamReader.EndOfStream);
            cantidadBytes = 0;
            int j = 0;
            int pos = -1;
            while ((i = streamReader.Read()) != -1)
            {
                dato = new Dato( (char)i );
                if ( (pos = pertenceALista(dato)) >= 0 )
                {
                    dato = listaFrecuencias[ pos ];
                    dato.aumentarCantidad();
                }
                else
                {
                    listaFrecuencias[_actualLF] = dato;
                    _actualLF++;
                    j++;
                }
            }

            streamReader.Close();

            imprimirLista("LISTA", listaFrecuencias);
        }

        private void imprimirLista(string linea,Dato[] lista)
        {
            System.Console.WriteLine( linea );
            char c;
            for (int k = 0; k < _actualLF; k++)
            {
                c = lista[k].Caracter;
                System.Console.WriteLine("L[" + k + "]=" + lista[k].Caracter +" #" + listaFrecuencias[k].Cantidad);
            }
        }

        private int pertenceALista(Dato dato)
        {
            int posRet = -1;
            int i = 0;
            bool encontro = false;
            while (i < _actualLF && !encontro)
            {
                if (dato.Caracter == listaFrecuencias[i].Caracter)
                {
                    posRet = i;
                    encontro = true;
                }

                i++;
            }

            return posRet;
        }

        #endregion


        #region METODOS DE COMPRESION
        private void Comprimir()
        {
            streamReader.Close();
            streamReader = new StreamReader(ruta);
            if (streamReader == null)
                return;

            int i;
            int valor;
            while ((i = streamReader.Read()) != -1)
            {
                if (hashTableFrecuencias.ContainsKey(i))
                {
                    valor = (int)hashTableFrecuencias[i];
                    //Si ya esta , lo elimino y lo agrego con una freq mas.
                    hashTableFrecuencias.Remove(i);
                    //Lo agrego nuevamente
                    hashTableFrecuencias.Add(i, ++valor);
                }
                else
                {
                    hashTableFrecuencias.Add(i, 1);
                }

                cantidadBytes++;
            }

        }

        #endregion




        #region auxiliarres
        private void CargarHasTable(string ruta)
        {
            streamReader = new StreamReader(ruta);
            if (streamReader == null)
                return;


            int i;
            cantidadBytes = 0;
            int valor;
            System.Console.WriteLine("StreamReader.Lenght = " + streamReader.EndOfStream);
            while ((i = streamReader.Read()) != -1)
            {
                //---------------HASH_TABLE-------------------------------
                if (hashTableFrecuencias.ContainsKey(i))
                {
                    valor = (int)hashTableFrecuencias[i];
                    //Si ya esta , lo elimino y lo agrego con una freq mas.
                    hashTableFrecuencias.Remove(i);
                    //Lo agrego nuevamente
                    hashTableFrecuencias.Add(i, ++valor);
                }
                else
                {
                    hashTableFrecuencias.Add(i, 1);
                }
                //---------------HASH_TABLE-------------------------------
                cantidadBytes++;
            }

            Console.WriteLine("CANTIDAD : " + cantidadBytes);

            foreach (Object o in hashTableFrecuencias.Keys)
            {
                System.Console.WriteLine("H" + (int)o + "=" + hashTableFrecuencias[o]);
            }

            streamReader.Close();
        }
        #endregion

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            try
            {
                _xIni = Int32.Parse(textBoxPosXraiz.Text);
                _yIni = Int32.Parse(textBoxPosYraiz.Text);

                if (_arbolHuffman != null)
                    MostrarArbol(_arbolHuffman.Raiz, _xIni, _yIni, true, 0, e.Graphics);
            }
            catch (Exception ex)
            {
                System.Console.WriteLine("En panel1_Paint(): " + ex.Message);
            }
        }

        private void buttonCodigo_Click(object sender, EventArgs e)
        {
            this.textBoxCodigo.Text = "";

            if (_arbolHuffman == null)
                return;

            string caracter = textBoxCaracter.Text;
            if (caracter.Length <= 0)
                return;

            caracter = _arbolHuffman.GetCodigo( caracter[0] );
            textBoxCodigo.Text = caracter;
        }

    }



}
